package com.store.service.impl;

import com.store.entity.User;
import com.store.mapper.UserMapper;
import com.store.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.store.service.ex.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.UUID;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author cai
 * @since 2022-07-09
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    UserMapper userMapper;

    @Override
    public void addUser(User user) {
        // 根据参数user对象获取注册的用户名
        String username=user.getUsername();
        // 调用持久层的User MyselectByUsername(String username)方法，根据用户名查询用户数据
        // 判断查询结果是否不为null
        // 是：表示用户名已被占用，则抛出UsernameDuplicateException异常
        if(userMapper.MyselectByUsername(username) !=null){
            throw new UsernameDuplicateeException("尝试注册的用户名[" + username + "]已经被占用");
        }
        // 创建当前时间对象
        LocalDateTime now =LocalDateTime.now();
        // 补全数据：加密后的密码
        String salt = UUID.randomUUID().toString().toUpperCase();
        String md5Password = getMd5Password(user.getPassword(), salt);
        user.setPassword(md5Password);
        // 补全数据：盐值
        user.setSalt(salt);
        // 补全数据：isDelete(0)
        user.setIsDelete(0);
        // 补全数据：4项日志属性
        user.setCreatedUser(username);
        user.setCreatedTime(now);
        user.setModifiedUser(username);
        user.setModifiedTime(now);

        // 表示用户名没有被占用，则允许注册
        // 调用持久层Integer insert(User user)方法，执行注册并获取返回值(受影响的行数)
        int result=userMapper.insert(user);
        // 判断受影响的行数是否不为1
        // 是：插入数据时出现某种错误，则抛出InsertException异常
        if (result!=1){
            throw new  InsertException("添加用户数据出现未知错误，请联系系统管理员");
        }
    }

    @Override
    public User Login(String username,String password) {
        // 调用持久层的User MyselectByUsername(String username)方法，根据用户名查询用户数据
        User user1=userMapper.MyselectByUsername(username);
        // 判断查询结果是否 为null 或者 已经被删除
        // 是：表示用户名不存在，否则抛出UserNotNxistException异常
        if(user1== null || user1.getIsDelete()==1){
            throw new UserNotNxistException("用户不存在");
        }
        // 判断输入的密码加密后是否正确
        // 是：表示密码错误 抛出PasswordException异常
        if( ! getMd5Password(password,user1.getSalt())
                .equals(user1.getPassword())){
            throw new PasswordException("密码错误");
        }
        // 创建新的User对象 信息保密
        User user = new User();
        // 将查询结果中的uid、username、avatar封装到新的user对象中
        user.setUid(user1.getUid());
        user.setUsername(user1.getUsername());
        user.setAvatar(user1.getAvatar());

        // 返回新的user对象
        return user;
    }

    @Override
    public void changePassword(int uid, String oldPassword,String newPassword) {
        //        基本逻辑
        //        User user=userMapper.selectById(uid);
        //        user.setPassword(password);
        //        userMapper.updateById(user);

        //判断新密码是否合理
        //是：抛出 PasswordException异常
        if(newPassword == null){
            throw new PasswordException("新密码不能为空");
        }
        // 调用持久层的 selectById(int uid)方法，根据uid查询用户数据
        User user=userMapper.selectById(uid);
        // 判断查询结果是否 为null 或者 已经被删除
        // 是：表示用户名不存在，否则抛出UserNotNxistException异常
        if(user== null || user.getIsDelete()==1){
            throw new UserNotNxistException("用户不存在");
        }
        // 从查询结果中取出盐值
        // 将参数oldPassword结合盐值加密，得到oldMd5Password
        // 判断查询结果中的password与oldMd5Password是否不一致
        // 是：抛出PasswordNotMatchException异常
        if( ! getMd5Password(oldPassword,user.getSalt())
                .equals(user.getPassword())){
            throw new PasswordException("原密码错误");
        }
        // 将参数newPassword结合盐值加密，得到newMd5Password
        // 创建当前时间对象
        // 调用userMapper的updatePasswordByUid()更新密码，并获取返回值
        // 判断以上返回的受影响行数是否不为1
        // 是：抛了UpdateException异常
        user.setPassword(getMd5Password(newPassword,user.getSalt()));
        user.setModifiedUser("用户申请,管理员修改");
        user.setModifiedTime(LocalDateTime.now());
        Integer rows=userMapper.updateById(user);
        if (rows != 1){
            throw new UpdateException("更新用户数据时出现未知错误，请联系系统管理员");
        }
    }

    @Override
    public User selectInfoByUid(int uid) {
        User user=userMapper.MySelectByUid(uid);
        // 判断查询结果是否 为null
        // 是：表示用户名不存在，否则抛出UserNotNxistException异常
        if(user== null){
            throw new UserNotNxistException("用户不存在");
        }
        return user;
    }

    @Override
    public void updateInfoByUid(int uid,String phone,String email,int gender) {
        // 调用持久层的 selectById(int uid)方法，根据uid查询用户数据
        User user= userMapper.selectById(uid);
        // 判断查询结果是否 为null 或者 已经被删除
        // 是：表示用户名不存在，否则抛出UserNotNxistException异常
        if(user== null || user.getIsDelete()==1){
            throw new UserNotNxistException("用户不存在");
        }
        //修改数据
        user.setPhone(phone);
        user.setEmail(email);
        user.setGender(gender);
        user.setModifiedUser("用户申请,管理员修改");
        user.setModifiedTime(LocalDateTime.now());

        Integer rows= userMapper.updateById(user);
        if (rows != 1){
            throw new UpdateException("更新用户数据时出现未知错误，请联系系统管理员");
        }
    }

    @Override
    public void upAvatar(int uid,String avatar) {
        // 调用持久层的 selectById(int uid)方法，根据uid查询用户数据
        User user= userMapper.selectById(uid);
        // 判断查询结果是否 为null 或者 已经被删除
        // 是：表示用户名不存在，否则抛出UserNotNxistException异常
        if(user== null || user.getIsDelete()==1){
            throw new UserNotNxistException("用户不存在");
        }
        //修改数据
        user.setAvatar(avatar);

        Integer rows= userMapper.updateById(user);
        if (rows != 1){
            throw new UpdateException("上传用户头像时出现未知错误，请联系系统管理员");
        }
    }

    /**
     * 执行密码加密
     * @param password 原始密码
     * @param salt 盐值
     * @return 加密后的密文
     */
    private String getMd5Password(String password, String salt) {
        /*
         * 加密规则：
         * 1、无视原始密码的强度
         * 2、使用UUID作为盐值，在原始密码的左右两侧拼接
         * 3、循环加密3次
         */
        for (int i = 0; i < 3; i++) {
            password = DigestUtils.md5DigestAsHex((salt + password +
                    salt).getBytes()).toUpperCase();
        }
        return password;
    }
}
